
import { _decorator, Component, Node, find, Color, UITransform, v2, Vec2 } from 'cc';
import { Delaunay } from '../Libs/Delaunay';
import { Config } from './Config';
import { Cell } from './Constructs/Cell';
import { MatrixGraph } from './Constructs/MatrixGraph';
import { QueueFunction } from './Constructs/QueueFunction';
import { TmpRoom } from './Constructs/TmpRoom';
import { DemoColors } from './Enums/DemoColors';
import { Calculator } from './Managers/Calculator';
import { FunctionQueue } from './Managers/FunctionQueue';
import { Renderer } from './Managers/Renderer';
import { CellNode } from './Prefabs/CellNode';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = Entrance
 * DateTime = Thu Sep 02 2021 18:09:49 GMT+0800 (中国标准时间)
 * Author = Squall
 * FileBasename = Entrance.ts
 * FileBasenameNoExtension = Entrance
 * URL = db://assets/Scripts/Entrance.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
 *
 */

@ccclass('Entrance')
export class Entrance extends Component {

    //内部参数
    private _scheduleSecond:number;
    private _funcId:number;

    //流程
    private _inited:boolean = false;
    //房间扩散完毕
    private seperateFinish:boolean = false;
    //Delaunay完毕
    private delaunayFinish:boolean = false;



    start() {
        this._init();
        this._startDemonstration();
    }

    // update (deltaTime: number) {
    //     // [4]
    // }

    /**
     * 开始演示流程
     */
    private _startDemonstration(){
        //控制器们
        let calculator: Calculator = find("Calculator").getComponent(Calculator);
        let renderer: Renderer = find("Renderer").getComponent(Renderer);
        const canvasTrans:UITransform = find("Canvas").getComponent(UITransform);

        //地图上所有Cell
        let oriMap:Array<Array<Cell>> = null;
        //地图上所有CellNode，用于表现
        let cellNodes:Array<Array<CellNode>> = null;
        //初始房间生成范围
        let areaCells:Array<Cell> = null;
        //room的定位点们
        let anchors:Array<Cell> = null;
        //所有房间
        let rooms:Array<TmpRoom> = null;
        //选出的主房间
        let mainRooms:Array<TmpRoom>
        //
        let graph:MatrixGraph = new MatrixGraph();

        //todo 初始化一片空白的背景用于表示地图范围
        this._addFunc(()=>{
            let mapWidth = canvasTrans.width;
            let mapHeight = canvasTrans.height;
            renderer.initMapArea(mapWidth,mapHeight);
            return true;
        },this._scheduleSecond++);

        //todo 将整个地图用格子表示
        this._addFunc(()=>{
            let mapWidth = canvasTrans.width;
            let mapHeight = canvasTrans.height;
            oriMap = calculator.getOriginMap(mapWidth,mapHeight, Config.CellIntervalRow, Config.CellIntervalCol);
            cellNodes = renderer.initMapNodes(oriMap);
            return true;
        },this._scheduleSecond++);

        //todo 标出生成初始房间的区域
        this._addFunc(()=>{
            areaCells = calculator.getRoomArea(oriMap);
            renderer.setCellArrayColor(cellNodes,areaCells,DemoColors.OriginArea);
            return true;
        },this._scheduleSecond++);

        //todo 生成房间的定位点
        this._addFunc(()=>{
            // anchors = [
            // calculator.getCell(oriMap,26,61),
            //     calculator.getCell(oriMap,28,61),
            //     calculator.getCell(oriMap,30,61)]
            anchors = calculator.getRoomAnchors(Config.RoomCount,areaCells);
            // console.log(anchors)
            renderer.setCellArrayColor(cellNodes,anchors,DemoColors.TmpRoomAnchorCell);
            return true;
        },this._scheduleSecond++);

        //todo 生成指定数量的房间
        this._addFunc(()=>{
            rooms = [];
            let testWH = [
                v2(5,2),
                v2(4,4),
                v2(4,2)];
            let whIdx = 0;
            for(let anchor of anchors){
                let tmpRoom:TmpRoom = calculator.getRoomByAnchor(anchor,oriMap);
                // let tmpRoom:TmpRoom = calculator.generateRoomWithLTAnchor(oriMap,anchor,testWH[whIdx].x,testWH[whIdx].y);
                whIdx++;
                rooms.push(tmpRoom);
            }
            for(let room of rooms){
                renderer.setRoomColor(cellNodes,room,rooms,false);
            }
            return true;
        },this._scheduleSecond++);

        //todo 房间扩散
        this._addFunc(()=>{
            this._spread(calculator,renderer,cellNodes,oriMap,rooms);
            return true;
        },this._scheduleSecond++);

        //todo 选出符合要求的房间
        this._addFunc(()=>{
            if(this.seperateFinish){
                mainRooms = calculator.getMainRooms(rooms);
                for(let room of rooms){
                    room.roomColor = DemoColors.TmpRoomDefaul;
                    renderer.setRoomColor(cellNodes,room,rooms,false);
                }
                this.scheduleOnce(()=>{
                    for(let room of mainRooms){
                        room.roomColor = DemoColors.MainRoom;
                        renderer.setRoomColor(cellNodes,room,rooms,false);
                    }
                },1)
                return true;
            }else{
                return false;
            }
        },0);

        //todo delaunay算法将选中的房间们之间连出道路
        this._addFunc(()=>{
            if(this.seperateFinish){
                this.scheduleOnce(()=>{
                    //生成全部房间的路线看看
                    // let roomVecs:Array<Array<number>> = calculator.getVecOfRooms(rooms);
                    //只生成主房间的道路
                    let roomVecs:Array<Array<number>> = calculator.getVecOfRooms(mainRooms);
                    roomVecs = graph.setAllPoint(roomVecs);
                    let triagles = Delaunay.Delaunay(roomVecs);
                    if(triagles.length === 0){
                        console.error("输入的点无法进行三角剖分")
                        return;
                    }
                    let lines = calculator.getLinesFromTriagles(triagles);
                    renderer.drawLines(roomVecs,lines,cellNodes,DemoColors.Line);

                    for(let line of lines){
                        let p1A = roomVecs[line[0]];
                        let p2A = roomVecs[line[1]];
                        let p1 = v2(p1A[0],p1A[1]);
                        let p2 = v2(p2A[0],p2A[1]);
                        graph.addEdge(line[0],line[1],Vec2.distance(p1,p2));
                    }
                    this.delaunayFinish = true;
                },2)
                return true;
            }else{
                return false;
            }
        },0);

        //todo 最小生成树剪掉多余道路
        this._addFunc(()=>{
            if(this.delaunayFinish){
                this.scheduleOnce(()=>{
                    let tree = graph.getMinimumSpanningTree();
                    let lines = graph.getLines(tree);
                    renderer.clearLines();
                    renderer.drawLines(graph.getAllPoints(),lines,cellNodes,DemoColors.RoadLine);
                },1)
                return true;
            }
            return false;
        },0)

        //todo 将直线边转换成格子道路

        //todo 保留道路经过的所有格子以增加地图丰富性，删除其余房间

        //todo 渲染地图
    }

    private _init(){
        if(this._inited) return;
        this._inited = true;
        this._funcId = 1;
        this._scheduleSecond = 0;
    }

    private _addFunc(func,delay){
        let func1 = new QueueFunction();
        func1.delay = delay;
        func1.id = this._funcId++;
        func1.mainFunc = func
        const functionQueue:FunctionQueue = find("FunctionQueue").getComponent(FunctionQueue);
        functionQueue.addFunction(func1);
    }
    
    private _spread(calculator:Calculator,renderer:Renderer,cellNodes:Array<Array<CellNode>>,oriMap:Array<Array<Cell>>,rooms:Array<TmpRoom>){
        let canSpread:boolean = true;
        canSpread = calculator.spreadOnce(oriMap,rooms);
        renderer.setCellArrayArrayColor(cellNodes,oriMap,DemoColors.CellDefault);
        for(let room of rooms){
            renderer.setRoomColor(cellNodes,room,rooms,false);
        }
        if(canSpread){
            let spreadInterval = 0;
            this.scheduleOnce(()=>{
                return this._spread(calculator,renderer,cellNodes,oriMap,rooms);
            },spreadInterval)
        }else{
            this.seperateFinish = true;
            return;
        }
    }
}

/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.3/manual/zh/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.3/manual/zh/scripting/ccclass.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.3/manual/zh/scripting/life-cycle-callbacks.html
 */
